package ar.edu.utn.frsf.cidisi.bbp.actions;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;

import ar.edu.utn.frsf.cidisi.bbp.BbpFactory;
import ar.edu.utn.frsf.cidisi.bbp.Node;
import ar.edu.utn.frsf.cidisi.bbp.OpeningConstruct;
import ar.edu.utn.frsf.cidisi.bbp.Tree;

public class Bbp2Mdb {
	
	private Tree bbp;
	
	private HashMap<String, Tree> mbdMap = new HashMap<String, Tree>();
	
	public Bbp2Mdb(Tree bbp){
		this.bbp = bbp;
		
	}
	
	
	public void generateMBD(Node root){

		List<Node> children = root.getChildren();

		for (int i=0;i<children.size();i++){

			List<Node> pivots = children.subList(0, i+1);
			List<Node> nodes = children.subList(i+1, children.size());
			
			if (root.getOpeningSemantics().equals(OpeningConstruct.SEQUENCE))
				generateMSD(root, pivots, nodes);				
			else if (!root.getOpeningSemantics().equals(OpeningConstruct.TERMINATION))
				generateMHD(root, pivots, nodes);
				
			Node pivot = children.get(i);
			
			generateMBD(pivot);
		}
		
		for (Tree t:mbdMap.values()){
			createBBPFile(t,t.getName());
		}
		
		
	}
	
	
	public void generateMHD(Node root,List<Node> pivots, List<Node> nodes){

		for (int i=0;i<pivots.size();i++){
			
			addMinimalHierarchicalProcesses(root,pivots.get(i),nodes);
			
			generateMHD(root,pivots.get(i).getChildren(),nodes);
			
		}
	
	}

	public void generateMSD(Node root,List<Node> pivots, List<Node> nodes){

		for (int i=0;i<pivots.size();i++){
			
			addMinimalSequentialProcesses(root,pivots.get(i),nodes);
			
//			generateMSD(root,pivots.get(i).getChildren(),nodes);
			
		}
	
	}
	
	private void addMinimalHierarchicalProcesses(Node root, Node pivot, List<Node> nodes){
		
		if (nodes.isEmpty() && 
				(root.getOpeningSemantics().equals(OpeningConstruct.LOOP_UNTIL) ||
						root.getOpeningSemantics().equals(OpeningConstruct.LOOP_WHILE))){
			
			addMinimalProcess(root,pivot,null);

		} else{
		
			for (int i=0;i<nodes.size();i++){
				
				Node n = nodes.get(i);
				
				addMinimalProcess(root,pivot,n);
				
				addMinimalHierarchicalProcesses(root,pivot,n.getChildren());
			
			}
		}
	}
	
	
	private void addMinimalSequentialProcesses(Node root, Node pivot, List<Node> nodes){
		
		for (int i=0;i<nodes.size();i++){
			
			Node n = nodes.get(i);
			
			addMinimalProcess(root,pivot,n);
			
//			addMinimalSequentialProcesses(root,pivot,n.getChildren());
		
		}
	}


	private void addMinimalProcess(Node root, Node pivot, Node n){
			
		Tree mProc = BbpFactory.eINSTANCE.createTree();
		
		Node newRoot = createNode(root);

		// Set the root of the minimal process
		mProc.setRoot(newRoot);

		// Set root's children
		Node newPivot = createNode(pivot);
		
		if (!pivot.getOpeningSemantics().equals(OpeningConstruct.SEQUENCE)){
			Node tempPivot = newPivot;
			newPivot = BbpFactory.eINSTANCE.createNode();
			newPivot.setOpeningSemantics(OpeningConstruct.SEQUENCE);
			newPivot.setId("Seq");
			newPivot.getChildren().add(tempPivot);
		}
		
		newRoot.getChildren().add(newPivot);
		
		if (n!=null){
			Node n2 = createNode(n);

			if (!n2.getOpeningSemantics().equals(OpeningConstruct.SEQUENCE)){
				Node tempPivot = n2;
				n2 = BbpFactory.eINSTANCE.createNode();
				n2.setOpeningSemantics(OpeningConstruct.SEQUENCE);
				n2.setId("Seq");
				n2.getChildren().add(tempPivot);
			}

			newRoot.getChildren().add(n2);
		}
		
		mProc.setName(getName(newRoot,pivot,n));

		mbdMap.put(mProc.getName(), mProc);		

	}
	
	
	private Node createNode(Node node){
		
		Node newNode = BbpFactory.eINSTANCE.createNode();
		
		newNode.setOpeningSemantics(node.getOpeningSemantics());
		newNode.setClosingSemantics(node.getClosingSemantics());
		newNode.setId(node.getId());
		
		return newNode;
	}

	
	private String getConnector(Node node){
		String connector = "";
		
		if (node.getOpeningSemantics().equals(OpeningConstruct.AND)
				|| node.getOpeningSemantics().equals(OpeningConstruct.OR)){
			
			connector = " X ";
		
		} else if (node.getOpeningSemantics().equals(OpeningConstruct.XOR)) {
			
			connector = " + ";
			
		} else if (node.getOpeningSemantics().equals(OpeningConstruct.SEQUENCE)) {
			
			connector = " -- ";
			
		}
		
		
		return connector;
	}
	
	private String getName(Node root, Node n1, Node n2){
		String name = "";
		Node nLeft = n1;
		Node nRight = n2;
		
	
		
		if (nRight!=null){

			// This is to place Sequence as the first node of the minimal process
			if (n2.getOpeningSemantics().equals(OpeningConstruct.SEQUENCE)){
				nLeft = n2;
				nRight = n1;
			}
		
			name = root.getId()+"-"+n1.getId()+getConnector(root)+n2.getId();
//			name = root.getOpeningSemantics().getName()+"-"+nLeft.getOpeningSemantics().getName()+getConnector(root)+nRight.getOpeningSemantics().getName();
		
		} else {

			name = root.getId()+"-"+n1.getId();
//			name = root.getOpeningSemantics().getName()+"-"+nLeft.getOpeningSemantics().getName();

		}
		
		return name;
	}

	
	/**
	 * Creates the BBP file.
	 * 
	 * @param resource The full path (including file name) to the new BBP file
	 * @return
	 *
	 * @author jmr
	 */
	public Resource createBBPFile(Tree mbd, String name) {

		// Get the resource path 
		String path = bbp.eResource().getURI().path();
		
		// Get the file name
		String fileName = bbp.eResource().getURI().lastSegment();
		
		// The full path to the new BBP file
		String newFileName = path.substring(0, path.indexOf(fileName)) + "MBD/"+name+".bbp";

		// create the resource and add the model to it
		ResourceSet resourceSet = new ResourceSetImpl();
		
		final URI uri = URI.createURI("platform:"+newFileName);
		
		final Resource newResource = resourceSet.createResource(uri);
		
		EList<EObject> contents = newResource.getContents();
		
		contents.add(mbd);
		
		try {
			
			newResource.save(new HashMap<Object, Object>());
			
		} catch (IOException e) {
			
			return null;
			
		}
		
		return newResource;

	}
	

}
